#region License
// WorkViewModel.cs
// 
// Copyright (c) 2012 Xoqal.com
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
// http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#endregion

namespace Shammateh.Win.UI.ViewModels
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Xoqal.Data;
    using Xoqal.Presentation.ViewModels;

    public class WorkViewModel : ShammatehCrudViewModel<Entities.Work>
    {
        #region Fields

        private readonly Data.IWorkRepository workRepository;
        private readonly Data.IActivityTypeRepository activityTypeRepository;
        private readonly Data.IResourceRepository resourceRepository;
        private readonly Data.IProjectRepository projectRepository;
        private readonly Data.IAudienceRepository audienceRepository;
        private Entities.Project filterProject;
        private DateTime? filterDate;
        private Entities.ActivityType filterActivityType;
        private Entities.Resource filterResource;
        private Entities.Audience filterAudience;
        private Entities.Project project;
        private Entities.ActivityType activityType;
        private Entities.Resource resource;
        private Entities.Audience audience;
        private List<ListItemViewModel> projects;
        private List<ListItemViewModel> activityTypes;
        private List<ListItemViewModel> resources;
        private List<ListItemViewModel> audiences;
        private int workCount;
        private double totalWorkTime;

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="WorkViewModel" /> class.
        /// </summary>
        /// <param name="unitOfWork">The unit of work.</param>
        /// <param name="workRepository">The work repository.</param>
        /// <param name="activityTypeRepository">The activity type repository.</param>
        /// <param name="resourceRepository">The resource repository.</param>
        /// <param name="projectRepository">The project repository.</param>
        /// <param name="audienceRepository">The audience repository.</param>
        public WorkViewModel(
            IUnitOfWork unitOfWork, 
            Data.IWorkRepository workRepository, 
            Data.IActivityTypeRepository activityTypeRepository,
            Data.IResourceRepository resourceRepository,
            Data.IProjectRepository projectRepository,
            Data.IAudienceRepository audienceRepository)
            : base(unitOfWork, workRepository)
        {
            this.workRepository = workRepository;
            this.activityTypeRepository = activityTypeRepository;
            this.resourceRepository = resourceRepository;
            this.projectRepository = projectRepository;
            this.audienceRepository = audienceRepository;
            this.FilterDate = DateTime.Now;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets the view title.
        /// </summary>
        /// <value>
        /// The view title.
        /// </value>
        public override string ViewTitle
        {
            get { return "فعالیت"; }
        }

        /// <summary>
        /// Gets or sets the filter project.
        /// </summary>
        /// <value>
        /// The filter project.
        /// </value>
        public Entities.Project FilterProject
        {
            get
            {
                return this.filterProject;
            }

            set
            {
                if (this.filterProject != value)
                {
                    this.filterProject = value;
                    this.RaisePropertyChanged(() => this.FilterProject);
                    this.UpdateData();
                }
            }
        }

        /// <summary>
        /// Gets or sets the filter date.
        /// </summary>
        /// <value>
        /// The filter date.
        /// </value>
        public DateTime? FilterDate
        {
            get
            {
                return this.filterDate;
            }

            set
            {
                if (this.filterDate != value)
                {
                    this.filterDate = value;
                    this.RaisePropertyChanged(() => this.FilterDate);
                    this.UpdateData();
                }
            }
        }

        /// <summary>
        /// Gets or sets the type of the filter activity.
        /// </summary>
        /// <value>
        /// The type of the filter activity.
        /// </value>
        public Entities.ActivityType FilterActivityType
        {
            get
            {
                return this.filterActivityType;
            }

            set
            {
                if (this.filterActivityType != value)
                {
                    this.filterActivityType = value;
                    this.RaisePropertyChanged(() => this.FilterActivityType);
                    this.UpdateData();
                }
            }
        }

        /// <summary>
        /// Gets or sets the filter resource.
        /// </summary>
        /// <value>
        /// The filter resource.
        /// </value>
        public Entities.Resource FilterResource
        {
            get
            {
                return this.filterResource;
            }

            set
            {
                if (this.filterResource != value)
                {
                    this.filterResource = value;
                    this.RaisePropertyChanged(() => this.FilterResource);
                    this.UpdateData();
                }
            }
        }

        /// <summary>
        /// Gets or sets the filter audience.
        /// </summary>
        /// <value>
        /// The filter audience.
        /// </value>
        public Entities.Audience FilterAudience
        {
            get
            {
                return this.filterAudience;
            }

            set
            {
                if (this.filterAudience != value)
                {
                    this.filterAudience = value;
                    this.RaisePropertyChanged(() => this.FilterAudience);
                    this.UpdateData();
                }
            }
        }

        /// <summary>
        /// Gets or sets the project.
        /// </summary>
        /// <value>
        /// The project.
        /// </value>
        public Entities.Project Project
        {
            get
            {
                return this.project;
            }

            set
            {
                if (this.project != value)
                {
                    this.project = value;
                    this.RaisePropertyChanged(() => this.Project);
                }
            }
        }

        /// <summary>
        /// Gets or sets the type of the activity.
        /// </summary>
        /// <value>
        /// The type of the activity.
        /// </value>
        public Entities.ActivityType ActivityType
        {
            get
            {
                return this.activityType;
            }

            set
            {
                if (this.activityType != value)
                {
                    this.activityType = value;
                    this.RaisePropertyChanged(() => this.ActivityType);
                }
            }
        }

        /// <summary>
        /// Gets or sets the resource.
        /// </summary>
        /// <value>
        /// The resource.
        /// </value>
        public Entities.Resource Resource
        {
            get
            {
                return this.resource;
            }

            set
            {
                if (this.resource != value)
                {
                    this.resource = value;
                    this.RaisePropertyChanged(() => this.Resource);
                }
            }
        }

        /// <summary>
        /// Gets or sets the audience.
        /// </summary>
        /// <value>
        /// The audience.
        /// </value>
        public Entities.Audience Audience
        {
            get
            {
                return this.audience;
            }

            set
            {
                if (this.audience != value)
                {
                    this.audience = value;
                    this.RaisePropertyChanged(() => this.Audience);
                }
            }
        }

        /// <summary>
        /// Gets or sets the projects.
        /// </summary>
        /// <value>
        /// The projects.
        /// </value>
        public List<ListItemViewModel> Projects
        {
            get
            {
                return this.projects;
            }

            set
            {
                if (this.projects != value)
                {
                    this.projects = value;
                    this.RaisePropertyChanged(() => this.Projects);
                }
            }
        }

        /// <summary>
        /// Gets or sets the activity types.
        /// </summary>
        /// <value>
        /// The activity types.
        /// </value>
        public List<ListItemViewModel> ActivityTypes
        {
            get
            {
                return this.activityTypes;
            }

            set
            {
                if (this.activityTypes != value)
                {
                    this.activityTypes = value;
                    this.RaisePropertyChanged(() => this.ActivityTypes);
                }
            }
        }

        /// <summary>
        /// Gets or sets the resources.
        /// </summary>
        /// <value>
        /// The resources.
        /// </value>
        public List<ListItemViewModel> Resources
        {
            get
            {
                return this.resources;
            }

            set
            {
                if (this.resources != value)
                {
                    this.resources = value;
                    this.RaisePropertyChanged(() => this.Resources);
                }
            }
        }

        /// <summary>
        /// Gets or sets the audiences.
        /// </summary>
        /// <value>
        /// The audiences.
        /// </value>
        public List<ListItemViewModel> Audiences
        {
            get
            {
                return this.audiences;
            }

            set
            {
                if (this.audiences != value)
                {
                    this.audiences = value;
                    this.RaisePropertyChanged(() => this.Audiences);
                }
            }
        }

        /// <summary>
        /// Gets or sets the total work time.
        /// </summary>
        /// <value>
        /// The total work time.
        /// </value>
        public double TotalWorkTime
        {
            get
            {
                return this.totalWorkTime;
            }

            set
            {
                if (this.totalWorkTime != value)
                {
                    this.totalWorkTime = value;
                    this.RaisePropertyChanged(() => this.TotalWorkTime);
                }
            }
        }

        /// <summary>
        /// Gets or sets the work count.
        /// </summary>
        /// <value>
        /// The work count.
        /// </value>
        public int WorkCount
        {
            get
            {
                return this.workCount;
            }

            set
            {
                if (this.workCount != value)
                {
                    this.workCount = value;
                    this.RaisePropertyChanged(() => this.WorkCount);
                }
            }
        }

        #endregion

        #region Protected Methods

        /// <summary>
        /// Updates the data.
        /// </summary>
        public override void UpdateData()
        {
            base.UpdateData();
            this.UpdateSummaries();
        }

        /// <summary>
        /// Gets the query.
        /// </summary>
        /// <returns></returns>
        protected override IQueryable<Entities.Work> GetQuery()
        {
            var query = this.workRepository.Query;

            if (this.FilterDate.HasValue)
            {
                DateTime today = this.FilterDate.Value.Date;
                DateTime tommorow = today.AddDays(1);
                query = query.Where(w => (w.StartTime >= today && w.StartTime < tommorow) ||
                                         (w.FinishTime >= today && w.FinishTime < tommorow));
            }

            if (this.FilterProject != null)
            {
                query = query.Where(w => w.ProjectId == this.FilterProject.Id);
            }

            if (this.FilterActivityType != null)
            {
                query = query.Where(w => w.ActivityTypeId == this.FilterActivityType.Id);
            }

            if (this.FilterResource != null)
            {
                query = query.Where(w => w.ResourceId == this.FilterResource.Id);
            }

            if (this.FilterAudience != null)
            {
                query = query.Where(w => w.AudienceId == this.FilterAudience.Id);
            }

            return query;
        }

        /// <summary>
        /// Called when refresh command execute.
        /// </summary>
        protected override void OnRefreshCommandExecute()
        {
            base.OnRefreshCommandExecute();
            this.LoadBasicInformtion();
        }

        /// <summary>
        /// Called when add command execute.
        /// </summary>
        protected override void OnAddCommandExecute()
        {
            base.OnAddCommandExecute();
            this.CurrentItem.StartTime = this.CurrentItem.FinishTime = DateTime.Now;
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Loads the basic information.
        /// </summary>
        private void LoadBasicInformtion()
        {
            this.Projects = this.projectRepository.GetAllItems().ToListItemViewModel(p => p.Title, true, "[انتخاب پروژه]").ToList();
            this.ActivityTypes = this.activityTypeRepository.GetAllItems().ToListItemViewModel(a => a.Title, true, "[انتخاب نوع فعالیت]").ToList();
            this.Resources = this.resourceRepository.GetAllItems().ToListItemViewModel(r => r.FullName, true, "[انتخاب فرد]").ToList();
            this.Audiences = this.audienceRepository.GetAllItems().ToListItemViewModel(a => a.FullName, true, "[انتخاب مخاطب]").ToList();
        }

        /// <summary>
        /// Updates the summaries.
        /// </summary>
        private void UpdateSummaries()
        {
            var times = this.GetQuery()
                .Select(w => new
                    {
                        StartTime = w.StartTime,
                        FinishTime = w.FinishTime
                    })
                .ToList();

            this.TotalWorkTime = times.Sum(t => (t.FinishTime - t.StartTime).TotalHours);

            this.WorkCount = this.GetDataItemCount();
        }

        #endregion
    }
}
